#pragma once

#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>

#include <queue>
#include <functional>
#include <exception>
#include <memory>
#include <cassert>


namespace tinyUtil {
    class TinyThreadPool {
    private:
        using Runnable = std::function<void(void)>;
        std::vector<std::unique_ptr<std::thread> > threads_;
        std::atomic<bool> running_{ false };

        mutable std::mutex mutex_;
        std::condition_variable notEmpty_;
        std::queue<Runnable> workQueue_;

        Runnable take();
        void start(unsigned numThreads);
    public:
        explicit TinyThreadPool(unsigned numThreads) {
            start(numThreads);
        }
        ~TinyThreadPool() { if (running_) stop(); }

        TinyThreadPool(const TinyThreadPool&) = delete;
        TinyThreadPool(TinyThreadPool&&) = delete;
        TinyThreadPool& operator=(const TinyThreadPool&) = delete;
        TinyThreadPool& operator=(TinyThreadPool&&) = delete;

        void run(Runnable task);
        void stop();

        size_t getQueueSize() const {
            std::unique_lock<std::mutex> lock { mutex_ };
            return workQueue_.size();
        }
    };
}

